unit id3;

interface

uses SysUtils, Classes, TntSysUtils, TntClasses;

const
  MaxID3Genre=147;
  ID3Genre: array[0..MaxID3Genre] of string = (
    'Blues', 'Classic Rock', 'Country', 'Dance', 'Disco', 'Funk', 'Grunge',
    'Hip-Hop', 'Jazz', 'Metal', 'New Age', 'Oldies', 'Other', 'Pop', 'R&B',
    'Rap', 'Reggae', 'Rock', 'Techno', 'Industrial', 'Alternative', 'Ska',
    'Death Metal', 'Pranks', 'Soundtrack', 'Euro-Techno', 'Ambient',
    'Trip-Hop', 'Vocal', 'Jazz+Funk', 'Fusion', 'Trance', 'Classical',
    'Instrumental', 'Acid', 'House', 'Game', 'Sound Clip', 'Gospel',
    'Noise', 'AlternRock', 'Bass', 'Soul', 'Punk', 'Space', 'Meditative',
    'Instrumental Pop', 'Instrumental Rock', 'Ethnic', 'Gothic',
    'Darkwave', 'Techno-Industrial', 'Electronic', 'Pop-Folk',
    'Eurodance', 'Dream', 'Southern Rock', 'Comedy', 'Cult', 'Gangsta',
    'Top 40', 'Christian Rap', 'Pop/Funk', 'Jungle', 'Native American',
    'Cabaret', 'New Wave', 'Psychadelic', 'Rave', 'Showtunes', 'Trailer',
    'Lo-Fi', 'Tribal', 'Acid Punk', 'Acid Jazz', 'Polka', 'Retro',
    'Musical', 'Rock & Roll', 'Hard Rock', 'Folk', 'Folk-Rock',
    'National Folk', 'Swing', 'Fast Fusion', 'Bebob', 'Latin', 'Revival',
    'Celtic', 'Bluegrass', 'Avantgarde', 'Gothic Rock', 'Progressive Rock',
    'Psychedelic Rock', 'Symphonic Rock', 'Slow Rock', 'Big Band',
    'Chorus', 'Easy Listening', 'Acoustic', 'Humour', 'Speech', 'Chanson',
    'Opera', 'Chamber Music', 'Sonata', 'Symphony', 'Booty Bass', 'Primus',
    'Porn Groove', 'Satire', 'Slow Jam', 'Club', 'Tango', 'Samba',
    'Folklore', 'Ballad', 'Power Ballad', 'Rhythmic Soul', 'Freestyle',
    'Duet', 'Punk Rock', 'Drum Solo', 'Acapella', 'Euro-House', 'Dance Hall',
    'Goa', 'Drum & Bass', 'Club-House', 'Hardcore', 'Terror', 'Indie',
    'BritPop', 'Negerpunk', 'Polsk Punk', 'Beat', 'Christian Gangsta Rap',
    'Heavy Metal', 'Black Metal', 'Crossover', 'Contemporary Christian',
    'Christian Rock', 'Merengue', 'Salsa', 'Trash Metal', 'Anime', 'Jpop',
    'Synthpop');

type

  TID3Rec = packed record
    Tag     : array[0..2] of Char;
    Title,
    Artist,
    Comment,
    Album   : array[0..29] of Char;
    Year    : array[0..3] of Char;
    Genre   : Byte;
  end;

  TID3Tag = class

  private
    procedure ResetData;
  public
    TagExists: Boolean;
    Title, Artist, Comment, Album, Year, Genre: WideString;
    constructor Create;
    destructor Destroy; override;
    function ReadTag(TagFile: WideString):Boolean;
end;

implementation

constructor TID3Tag.Create;
begin
  inherited Create;
  ResetData;
  TagExists := false;
end;

destructor TID3Tag.Destroy;
begin
  inherited;
end;

procedure TID3Tag.ResetData;
begin
  Title := '';
  Artist := '';
  Comment := '';
  Album := '';
  Year := '';
  Genre := '';
end;

function TID3Tag.ReadTag(TagFile: WideString):Boolean;
var ID3 : TID3Rec;
    FS: TTntFileStream;
begin
  if WideFileExists(TagFile) then
  begin
    try
      FS := TTntFileStream.Create(TagFile, fmOpenRead);
    except
      Result := false;
      Exit;
    end;
    try
      ResetData;
      TagExists := false;
      FS.position := FS.size - 128;
      FS.Read(ID3, SizeOf(ID3));
    finally
      FS.free;
    end;

    if ID3.Tag <> 'TAG'
    then TagExists := false
    else
    begin
      TagExists := true;

      Title := Trim(ID3.Title);
      Artist := Trim(ID3.Artist);
      Album := Trim(ID3.Album);
      Year := Trim(ID3.Year);

      if ID3.Genre in [0..MaxID3Genre]
      then Genre := ID3Genre[ID3.Genre]
      else Genre := IntToStr(ID3.Genre);

      Comment := Trim(ID3.Comment);
    end;
    Result := true;
  end
  else Result := false;
end;

end.
